using Engine.Graphics.VertexStructures;
using SharpDX;
using SharpDX.Direct3D11;
using System;

namespace Scenario_Editor.Tools
{
    public class _dCursor
    {
        #region Private Fields

        private Vector3 center;
        private Engine.Engine device;
        private bool disable = true;
        private int nSides = 20;
        private Vector3[] positions;
        private SharpDX.Direct3D11.Buffer vb;
        private VertexBufferBinding vertexBufferBinding;
        private BufferDescription vertexBufferDescription;
        private CustomVertex.PositionColored[] vertices;

        #endregion Private Fields

        #region Public Constructors

        public _dCursor(Engine.Engine device, Vector3 position, float size, System.Drawing.Color Color)
        {
            this.device = device;

            vertexBufferDescription = new BufferDescription()
            {
                BindFlags = BindFlags.VertexBuffer,
                CpuAccessFlags = 0,
                SizeInBytes = (2 + nSides) * CustomVertex.PositionColored.SizeInBytes(),
                Usage = ResourceUsage.Default
            };

            vertices = new CustomVertex.PositionColored[2 + nSides];
            positions = new Vector3[nSides];
            this.center = position;
            CalculateVertex(position, Color, size);
        }

        #endregion Public Constructors

        #region Public Properties

        public bool Disable
        {
            set
            {
                this.disable = value;
            }
        }

        #endregion Public Properties

        #region Internal Properties

        internal Vector3 Center
        {
            get
            {
                return this.center;
            }
        }

        internal Vector3[] Positions
        {
            get
            {
                return this.positions;
            }
            set
            {
                UpdatePositions(value);
                this.positions = value;
            }
        }

        #endregion Internal Properties

        #region Public Methods

        public void CalculateVertex(Vector3 position, System.Drawing.Color color, float radius)
        {
            this.center = position;
            // Calculate Vertices for the circle
            for (int r = 0; r < nSides; r++)
            {
                float theta = (float)(2 * Math.PI * r) / (nSides - 1);
                float x = (float)Math.Sin(theta) * radius;
                float y = (float)Math.Cos(theta) * radius;
                vertices[r].X = position.X + x;
                vertices[r].Y = position.Y;
                vertices[r].Z = position.Z + y;
                vertices[r].Color = new Color4(color.ToArgb());
                positions[r] = vertices[r].Position;
            }
            vertices[vertices.Length - 2].Position = position;
            vertices[vertices.Length - 2].Color = new Color4(color.ToArgb());
            vertices[vertices.Length - 1].Position = new Vector3(position.X, position.Y - 2000.0f, position.Z);
            vertices[vertices.Length - 2].Color = new Color4(color.ToArgb());

            disable = false;
        }

        public void Draw()
        {
            if (disable)
                return;

            DeviceContext deviceContext = this.device.Grafic.Device.ImmediateContext;
            lock (deviceContext)
            {
                this.device.Grafic.ShaderManager.SetShader(this.device.Grafic.ShaderManager.ColorShader);

                deviceContext.InputAssembler.SetVertexBuffers(0, this.vertexBufferBinding);
                deviceContext.InputAssembler.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.LineStrip;
                deviceContext.Draw(vertices.Length - 2, 0);
                deviceContext.Draw(2, vertices.Length - 2);
            }

            this.disable = true;
        }

        #endregion Public Methods

        #region Internal Methods

        internal void Dispose()
        {
            if (this.vb != null)
                this.vb.Dispose();
            this.vb = null;
        }

        internal void Update(Vector3 position, float radius, System.Drawing.Color color)
        {
            CalculateVertex(position, color, radius);
            UpdateVertexBuffer();
        }

        #endregion Internal Methods

        #region Private Methods

        private void UpdatePositions(Vector3[] positions)
        {
            for (int r = 0; r < positions.Length; r++)
            {
                vertices[r].Position = positions[r];
            }

            UpdateVertexBuffer();
        }

        private void UpdateVertexBuffer()
        {
            this.vertexBufferDescription.SizeInBytes = (2 + nSides) * CustomVertex.PositionColored.SizeInBytes();
            int newSize = (2 + nSides) * CustomVertex.PositionColored.SizeInBytes();

            if (vb == null || newSize != this.vertexBufferDescription.SizeInBytes)
            {
                this.vertexBufferDescription.SizeInBytes = newSize;
                if (vb != null)
                    vb.Dispose();
                vb = null;
                lock (this.device.Device.ImmediateContext)
                {
                    this.vb = SharpDX.Direct3D11.Buffer.Create(this.device.Grafic.Device, vertices, this.vertexBufferDescription);
                    this.vertexBufferBinding = new VertexBufferBinding(this.vb, CustomVertex.PositionColored.SizeInBytes(), 0);
                }
            }
            else
                lock (this.device.Device.ImmediateContext)
                    this.device.Device.ImmediateContext.UpdateSubresource(vertices, this.vb);
        }

        #endregion Private Methods
    }
}